// System includes
#include <QDebug>

// Local includes
#include "yigpacketlistener.h"

extern bool ONLINE;
extern QString USER_NAME;

void YigPacketListener::ProcessMessage(const osc::ReceivedMessage &message, const IpEndpointName &remoteEndpoint)
{
    //qDebug() << message.AddressPattern();

    try {
        // Status Reply from SCSynth
        if( strcmp( message.AddressPattern(), "/status.reply" ) == 0 ){

            osc::ReceivedMessageArgumentStream args = message.ArgumentStream();
            osc::int32 un, numUGens, numSynths, numGroups, numSynthDefs;

            float avgCPU,peakCPU;
            double nominalSR,actualSR;

            //args >> un >> numUGens >> numSynths >> numGroups >> numSynthDefs
            //        >> avgCPU >> peakCPU >> nominalSR >> actualSR >> osc::EndMessage;

            args >> un >> numUGens >> numSynths >> numGroups >> numSynthDefs
                    >> avgCPU >> peakCPU >> nominalSR >> actualSR >> osc::EndMessage;

            emit serverStatus("running", numSynths, avgCPU, peakCPU);

            /**
            qDebug() << "Number Of Ugens: " << numUGens << " Number Of Synths: " << numSynths
                     << " Number Of Groups: " <<  numGroups << " Number Of Synth Defs: " << numSynthDefs
                     << " Avg CPU: " << avgCPU << " PeakCPU: " << peakCPU
                     << " Nominal Sample Rate: " << nominalSR << " Actual Sample Rate: " << actualSR;
                     */

        }

        if(ONLINE)
        {
            if(strcmp( message.AddressPattern(), "/addSyncObject" ) == 0) {

                osc::ReceivedMessage::const_iterator arg = message.ArgumentsBegin();

                // [0] map key
                const char* mapKey = (arg++)->AsString();
                const char* objectType = (arg++)->AsString();
                const char* objectSubType = (arg++)->AsString();

                //qDebug() << "SUBTYPE: " << objectSubType;

                if(strcmp(objectSubType, "SynthObject") == 0)
                {
                    const char* synthName = (arg++)->AsString();
                    int xPos, yPos;
                    float param1, param2;
                    xPos = (arg++)->AsInt32();
                    yPos = (arg++)->AsInt32();
                    param1 = (arg++)->AsFloat();
                    param2 = (arg++)->AsFloat();
                    //qDebug() << "NEW SYNTH " <<  mapKey;
                    emit addSynth(QString(mapKey), QString(synthName), QPoint(xPos, yPos), param1, param2);
                }

            } else if(strcmp( message.AddressPattern(), "/removeSyncObject" ) == 0) {

                osc::ReceivedMessage::const_iterator arg = message.ArgumentsBegin();

                const char* mapKey = (arg++)->AsString();
                emit removeSynth(mapKey);

            } else if(strcmp( message.AddressPattern(), "/setSyncArg" ) == 0) {

                osc::ReceivedMessage::const_iterator arg = message.ArgumentsBegin();
                const char* type;

                /*
                qDebug() << "SYNC ARGS!";
                QString mapKey = QString((arg++)->AsString());
                int argNum = (arg++)->AsInt32();
                while(arg != message.ArgumentsEnd())
                {
                    qDebug() << (arg++)->AsFloat();
                }*/


                int numArgs = message.ArgumentCount();

                for(int i = 0; i < numArgs; i++)
                {

                    if(i == (numArgs-1))
                    {
                        type = (arg++)->AsString();
                    }

                    else
                    {
                        arg++;
                    }
                }

                if(strcmp(type, "SynthObject") == 0)
                {
                    //qDebug() << "SET ARG!!!!!!!!";
                    arg = message.ArgumentsBegin();
                    QString mapKey = QString((arg++)->AsString());
                    int argNum = (arg++)->AsInt32();
                    //qDebug() << "SYNC ARG NUM: " << argNum;

                    // arg[0] = map key, arg[1] = xPos, arg[2] = yPos, arg[3] = param1, arg[4] = param2
                    switch(argNum)
                    {
                    case 0:
                        //qDebug() << "Synth Name" << (arg++)->AsString();
                        emit synthNameSync(mapKey, QString((arg++)->AsString()));
                        break;
                    case 1:
                        //qDebug() << "Set xPos";
                        emit updateSynthPositionX(mapKey, (arg++)->AsInt32());
                        break;
                    case 2:
                        //qDebug() << "Set yPos";
                        emit updateSynthPositionY(mapKey, (arg++)->AsInt32());
                        break;
                    case 3:
                        //qDebug() << "Set Param1";
                        emit updateSynthParam1(mapKey, (arg++)->AsFloat());
                        break;
                    case 4:
                        //qDebug() << "Set Param2";
                        emit updateSynthParam2(mapKey, (arg++)->AsFloat());
                        break;
                    case 5:
                        emit updateSynthSelected(mapKey, QString((arg++)->AsString()));
                        break;
                    }
                }

                else if(strcmp(type, "CursorObject") == 0)
                {
                    arg = message.ArgumentsBegin();
                    QString userName = QString((arg++)->AsString());
                    int argNum = (arg++)->AsInt32();
                    //qDebug() << "CursorObject user: " << userName;
                    switch(argNum)
                    {
                    case 0:
                        //qDebug() << "Cursor X";
                        emit updateCursorPositionX(userName, (arg++)->AsInt32());
                        break;
                    case 1:
                        //qDebug() << "Cursor Y";
                        emit updateCursorPositionY(userName, (arg++)->AsInt32());
                        break;
                    }
                }

                //void updateSynthPosition(QString mapKey, QPoint point);
                //void updateSynthParam1(QString mapKey, float param1);\
                //void updateSynthParam1(QString mapKey, float param2);

            } else if(strcmp( message.AddressPattern(), "/chat" ) == 0) {

                osc::ReceivedMessageArgumentStream args = message.ArgumentStream();
                const char* message;
                args >> message >> osc::EndMessage;
                emit chatMessage(QString(message));

            } else if(strcmp( message.AddressPattern(), "/addPeer" ) == 0) {

                osc::ReceivedMessageArgumentStream args = message.ArgumentStream();
                const char* userName;
                args >> userName >> osc::EndMessage;
                emit addPeer(QString(userName));

            } else if(strcmp( message.AddressPattern(), "/removePeer" ) == 0) {

                osc::ReceivedMessageArgumentStream args = message.ArgumentStream();
                const char* userName;
                args >> userName >> osc::EndMessage;
                emit removePeer(QString(userName));

            } else if( strcmp( message.AddressPattern(), "/userName" ) == 0 ){
                osc::ReceivedMessage::const_iterator arg = message.ArgumentsBegin();
                USER_NAME = (arg++)->AsString();
                qDebug() <<"userName is: " << USER_NAME;
                emit userNameReply();
            } else {

                osc::ReceivedMessage::const_iterator arg = message.ArgumentsBegin();

                while( arg != message.ArgumentsEnd() )
                {
                    qDebug() << ( arg++ ) -> AsString();
                }

                qDebug() << "\n";
            }
        }



    } catch( osc::Exception& e ) {

        qDebug() << "error while parsing message: "
                << message.AddressPattern( ) <<": " << e.what( ) << "\n";
    }
}
